﻿// CDlgRebarCustom.cpp: 实现文件
//

#include "Stdafx.h"
#include "CDlgRebarCustom.h"
#include "afxdialogex.h"
#include "Keeper.h"
#include "ArxSelector.h"
#include "ArxDatabase.h"
#include "Conver.h"
#include <fstream>
#include <filesystem>
#include <xlocale>

CDlgRebarCustom* CDlgRebarCustom::s_instance = nullptr;

// CDlgRebarCustom 对话框

IMPLEMENT_DYNAMIC(CDlgRebarCustom, CDialogEx)

CDlgRebarCustom::CDlgRebarCustom(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_DIALOG_REBAR_CUSTOM, pParent)
{

}

CDlgRebarCustom::~CDlgRebarCustom()
{
}

void CDlgRebarCustom::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_EDIT_CODE, m_rebarCode);
}

LRESULT CDlgRebarCustom::OnAcadKeepFocus(WPARAM, LPARAM)
{
	return TRUE;
}

BEGIN_MESSAGE_MAP(CDlgRebarCustom, CDialogEx)
	ON_MESSAGE(WM_ACAD_KEEPFOCUS, OnAcadKeepFocus)
	ON_BN_CLICKED(IDC_BUTTON_DRAW_LINE, &CDlgRebarCustom::OnBnClickedButtonDrawLine)
	ON_BN_CLICKED(IDC_BUTTON_DRAW_ARC, &CDlgRebarCustom::OnBnClickedButtonDrawArc)
	ON_BN_CLICKED(IDC_BUTTON_DRAW_CIRCLE, &CDlgRebarCustom::OnBnClickedButtonDrawCircle)
	ON_BN_CLICKED(IDC_BUTTON_DRAW_POLYLINE, &CDlgRebarCustom::OnBnClickedButtonDrawPolyline)
	ON_BN_CLICKED(IDOK, &CDlgRebarCustom::OnBnClickedOk)
	ON_BN_CLICKED(IDC_BUTTON_SET_BASE, &CDlgRebarCustom::OnBnClickedButtonSetBase)
	ON_BN_CLICKED(IDC_BUTTON_PICK_POLYLINE, &CDlgRebarCustom::OnBnClickedButtonPickPolyline)
ON_WM_CLOSE()
END_MESSAGE_MAP()


// CDlgRebarCustom 消息处理程序

CDlgRebarCustom* CDlgRebarCustom::GetInstance()
{
	if (s_instance == nullptr)
	{
		s_instance = new CDlgRebarCustom();
		s_instance->Create(IDD_DIALOG_REBAR_CUSTOM, acedGetAcadFrame());
	}

	return s_instance;
}


void CDlgRebarCustom::OnBnClickedButtonDrawLine()
{
	Keeper&& _keeper = Disposable::ProvisionalHide(this->GetParentOwner());

	AcGePoint3d startPoint, endPoint;

	if (CArxSelector::GetCurrentDocSelector().GetPoint(_T("\n请指定起点:"), startPoint)
		&&
		CArxSelector::GetCurrentDocSelector().GetPoint(startPoint, _T("\n请指定终点:"), endPoint)
		)
	{
		AcDbObjectId lineId;
		if (eOk == CArxDatabase::GetCurrentDatabase().DrawLine(startPoint, endPoint, lineId))
		{
			AcDbObjectId dimId;
			CArxDatabase::GetCurrentDatabase().DimEntity(lineId, dimId);

			McRebarDetailGraphLine* pMcGraphLine = new McRebarDetailGraphLine();
			pMcGraphLine->startPoint = startPoint;
			pMcGraphLine->endPoint = endPoint;
			m_graphIdMap[lineId] = pMcGraphLine;
			m_dimIdExprMap[dimId ] = &pMcGraphLine->exprLength;
		}
	}
}


void CDlgRebarCustom::OnBnClickedButtonDrawArc()
{
	Keeper&& _keeper = Disposable::ProvisionalHide(this->GetParentOwner());

	AcGePoint3d pnt, startPoint, endPoint;

	double radius = 0;

	if (
		CArxSelector::GetCurrentDocSelector().GetPoint(_T("\n请指定弧的起点:"), startPoint)
		&&
		CArxSelector::GetCurrentDocSelector().GetPoint(_T("\n请指定弧要过的点:"), pnt)
		&&
		CArxSelector::GetCurrentDocSelector().GetPoint(_T("\n请指定弧的端点:"), endPoint)
		)
	{
		AcDbObjectId arcId;
		if (eOk == CArxDatabase::GetCurrentDatabase().DrawArc(startPoint, pnt, endPoint, arcId))
		{
			AcDbObjectId dimId;
			CArxDatabase::GetCurrentDatabase().DimEntity(arcId, dimId);

			McRebarDetailGraphArc* pMcGraphArc = new McRebarDetailGraphArc();
			pMcGraphArc->startPoint = startPoint;
			pMcGraphArc->pnt = pnt;
			pMcGraphArc->endPoint = endPoint;

			m_graphIdMap[arcId] = pMcGraphArc;
			m_dimIdExprMap[dimId] = &pMcGraphArc->exprRadius;
		}
	}
}

void CDlgRebarCustom::OnBnClickedButtonDrawCircle()
{
	Keeper&& _keeper = Disposable::ProvisionalHide(this->GetParentOwner());

	AcGePoint3d pointCenter, point;

	double radius = 0;

	if (CArxSelector::GetCurrentDocSelector().GetPoint(_T("\n请指定圆心:"), pointCenter)
		&&
		CArxSelector::GetCurrentDocSelector().GetPoint(_T("\n请指定圆要过的点:"), point)
		)
	{
		AcDbObjectId circleId;
		if (eOk == CArxDatabase::GetCurrentDatabase().DrawCircle(pointCenter, point, circleId))
		{
			AcDbObjectId dimId;
			CArxDatabase::GetCurrentDatabase().DimEntity(circleId, dimId);

			McRebarDetailGraphCircle* pMcGraphCircle = new McRebarDetailGraphCircle();
			pMcGraphCircle->centerPoint = pointCenter;
			pMcGraphCircle->radius = pointCenter.distanceTo(point);

			m_graphIdMap[circleId] = pMcGraphCircle;
			m_dimIdExprMap[dimId] =&pMcGraphCircle->exprRadius;
		}
	}
}


void CDlgRebarCustom::OnBnClickedButtonDrawPolyline()
{
	Keeper&& _keeper = Disposable::ProvisionalHide(this->GetParentOwner());

	AcGePoint3d pointStart, pointNext;

	if (CArxSelector::GetCurrentDocSelector().GetPoint(_T("\n请指定起点:"), pointStart)
		&&
		CArxSelector::GetCurrentDocSelector().GetPoint(pointStart, _T("\n请指定下一个点:"), pointNext))
	{
		double minRadius = pointStart.distanceTo(pointNext) / 2.0;

		CString sPrompt;
		sPrompt.Format(_T("\n请输入半径<默认0，最小绝对值%.2f>:"), minRadius);


		double radius = 0;
		CArxSelector::GetCurrentDocSelector().GetReal(sPrompt, radius);

		double bulge = Conver::Radius2Bulge(pointStart.distanceTo(pointNext), radius);

		AcDbObjectId eId;
		CArxDatabase::GetCurrentDatabase().DrawPolyLine(pointStart, pointNext, bulge, eId);

		McRebarDetailGraphPolyLine* pMcGraphPolyLine = new McRebarDetailGraphPolyLine();
		m_graphIdMap[eId] = pMcGraphPolyLine;

		auto startVertex = new McRebarDetailGraphPolyLineVertex(pointStart);
		pMcGraphPolyLine->vertexs.push_back(startVertex);

		AcGeCircArc3d arc;
		CArxDatabase::GetCurrentDatabase().GetPolyLineLastArc(eId, arc);
		AddVertex(pMcGraphPolyLine, pointNext, pointStart, arc, bulge, eId);

		pointStart = pointNext;

		while (CArxSelector::GetCurrentDocSelector().GetPoint(pointStart, _T("\n请指定下一个点:"), pointNext))
		{
			minRadius = pointStart.distanceTo(pointNext) / 2.0;

			sPrompt.Format(_T("\n请输入半径<默认0，最小%.2f>:"), minRadius);

			radius = 0;
			CArxSelector::GetCurrentDocSelector().GetReal(sPrompt, radius);
			
			bulge = Conver::Radius2Bulge(pointStart.distanceTo(pointNext), radius);

			CArxDatabase::GetCurrentDatabase().AddPolyLineVertex(eId, pointNext, bulge);

			AcGeCircArc3d arc;
			CArxDatabase::GetCurrentDatabase().GetPolyLineLastArc(eId, arc);
			AddVertex(pMcGraphPolyLine, pointNext, pointStart, arc, bulge, eId);
			
			pointStart = pointNext;
		}
	}
}


void CDlgRebarCustom::AddVertex(McRebarDetailGraphPolyLine* pMcGraphPolyLine, const AcGePoint3d& pointNext, const AcGePoint3d& pointStart, const AcGeCircArc3d& arc, double bulge, const AcDbObjectId& eId)
{
	auto nextVertex = new McRebarDetailGraphPolyLineVertex(pointNext);

	AcDbObjectId dimId;
	if (bulge == 0)
	{
		nextVertex->expr.expr.Format(_T("%f"), pointStart.distanceTo(pointNext));
		CArxDatabase::GetCurrentDatabase().DimLine(pointStart, pointNext, dimId);
	}
	else
	{
		nextVertex->bulge = bulge;
		nextVertex->expr.expr.Format(_T("%f"), arc.radius());
		CArxDatabase::GetCurrentDatabase().DimArc(arc, dimId);
	}

	m_dimIdExprMap[dimId] = &nextVertex->expr;
	pMcGraphPolyLine->vertexs.push_back(nextVertex);
}

void CDlgRebarCustom::OnBnClickedOk()
{

	CString code;
	m_rebarCode.GetWindowTextW(code);

	if (code.IsEmpty())
	{
		MessageBox(L"钢筋大样代号不能为空");
		m_rebarCode.SetFocus();
		return;
	}

	McRebarDetailData data;
	data.code = code;
	data.graphData.basePoint = m_basePoint;

	//获取最新的标注文本写入到expr对象中
	for (auto it = m_dimIdExprMap.begin(); it != m_dimIdExprMap.end(); ++it)
	{
		AcDbObject* pObject = nullptr;
		if (CArxDatabase::GetCurrentDatabase().OpenAcDbObject(it->first, pObject))
		{
			AcDbDimension* pDimension = AcDbDimension::cast(pObject);

			if (pDimension)
			{
				it->second->expr = pDimension->dimensionText();
			}

			pObject->close();
		}
	}

	//填充图形数据
	for (auto it = m_graphIdMap.begin(); it != m_graphIdMap.end(); ++it)
	{
		//过滤掉已经被删除的图形
		if (CArxDatabase::GetCurrentDatabase().IsErase(it->first))
		{
			delete it->second;
		}
		else
		{
			data.graphData.graphDataList.push_back(it->second);
		}
	}

	Save(data);

	Clear();

	// TODO: 在此添加控件通知处理程序代码
	CDialogEx::OnOK();
}

void CDlgRebarCustom::Save(const McRebarDetailData& data)
{
	configor::wjson wj = Conver::McRebarDetailData2Json(data);
	//...文件打开，保存信息，关闭文件等操作。
	CString outFile = RebarLibPath;
	outFile += data.code + _T(".json");
	std::filesystem::path outPath(outFile.GetString());
	std::filesystem::create_directories(outPath.parent_path());

	std::locale oNewLocale(std::locale(), "", std::locale::ctype);
	std::locale oPreviousLocale = std::locale::global(oNewLocale);
	std::wofstream wofs(outPath, std::ios::out | std::ios::trunc);
	if (wofs.is_open())
	{
		std::wstring content = wj.dump();
		wofs << content << std::endl;
		wofs.close();
		MessageBox(outPath.wstring().c_str());
	}
	std::locale::global(oPreviousLocale);
}

void CDlgRebarCustom::Clear()
{
	for (auto& pair : m_dimIdExprMap)
	{
		CArxDatabase::GetCurrentDatabase().Erase(pair.first);
	}

	m_rebarCode.SetWindowTextW(_T(""));
	m_dimIdExprMap.clear();
	m_graphIdMap.clear();
	m_basePoint = AcGePoint3d::kOrigin;
}

void CDlgRebarCustom::OnBnClickedButtonSetBase()
{
	Keeper&& _keeper = Disposable::ProvisionalHide(this->GetParentOwner());

	AcGePoint3d basePoint;
	if (CArxSelector::GetCurrentDocSelector().GetPoint(_T("\n请指定基点:"), basePoint))
	{
		m_basePoint = basePoint;
	}
}


void CDlgRebarCustom::OnBnClickedButtonPickPolyline()
{
	Keeper&& _keeper = Disposable::ProvisionalHide(this->GetParentOwner());

	AcDbObjectIdArray ids;
	CArxSelector::GetCurrentDocSelector().SelectEntitys(_T("请选择多段线"), ids);
	
	for (int i = 0; i < ids.length(); ++i)
	{
		AcDbObjectId& eId = ids[i];

		if (!CArxDatabase::GetCurrentDatabase().IsKindOf(eId, AcDbPolyline::desc()))
		{
			continue;
		}

		AcDbEntityPointer entity(eId, AcDb::kForRead);

		if (entity.openStatus() != eOk)
		{
			return;
		}

		AcDbPolyline* polyline = (AcDbPolyline*)entity.object();

		McRebarDetailGraphPolyLine* pMcGraphPolyLine = new McRebarDetailGraphPolyLine();
		m_graphIdMap[eId] = pMcGraphPolyLine;

		AcGePoint3d pointStart;
		polyline->getPointAt(0, pointStart);
		auto startVertex = new McRebarDetailGraphPolyLineVertex(pointStart);
		pMcGraphPolyLine->vertexs.push_back(startVertex);

		for (unsigned int i = 1; i < polyline->numVerts(); ++i)
		{
			AcGePoint3d prePoint;
			AcGePoint3d curPoint;
			double bulge = 0;
			polyline->getPointAt(i, curPoint);
			polyline->getPointAt(i - 1, prePoint);
			polyline->getBulgeAt(i - 1, bulge);

			AcGeCircArc3d arc;
			polyline->getArcSegAt(i - 1, arc);
			AddVertex(pMcGraphPolyLine, curPoint, prePoint, arc, bulge, eId);
		}

		if (polyline->isClosed())
		{
			AcGePoint3d prePoint;
			AcGePoint3d curPoint;
			double bulge = 0;
			polyline->getPointAt(0, curPoint);
			polyline->getPointAt(polyline->numVerts() - 1, prePoint);
			polyline->getBulgeAt(polyline->numVerts() - 1, bulge);

			AcGeCircArc3d arc;
			polyline->getArcSegAt(polyline->numVerts() - 1, arc);
			AddVertex(pMcGraphPolyLine, curPoint, prePoint, arc, bulge, eId);
		}
	}
}

void CDlgRebarCustom::OnClose()
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	Clear();

	CDialogEx::OnClose();
}
